리액트 코드스멜과 클린코드 작성에 대해. 참조영상
당연한 얘기지만 오랫동안 좋은 코드를 유지하고 관리하기 위해선 소통이 가장 중요하다.
UI툴킷에 UserAvatar
컴포넌트가 있다고 가정하자. UserAvatar 컴포넌트는 지정된 크기를 입력받을 수 있다. 예를 들어 small, medium, large
의 크기가 있다고 치자.
어느날 메신저 채팅 기능이 생겨났고 각 채팅 한줄마다 UserAvatar
, 사용자 이름, 텍스트의 내용이 들어가야한다고 하자. 그런데 채팅에 쓰이는 UserAvatar
의 크기가 기존 small, medium, large
에 맞지 않고 meium
과 large
사이의 애매한 크기였다.
그래서 medium
과 large
사이 어떤 이름이 들어가야할지 고민하다가 message
라는 크기명을 주기로 했다. 결국 메세지 기능과 전혀 무관한 곳에서 해당 사이즈를 이곳 저곳 참조하게 되었다. BAD END
특정한 기능에 대한 정보(예: 메신저)가 일반적으로 사용되는 Generic한 컴포넌트와 엮이면 안된다. 이런 경우를 정보가 새어나간다고 표현할 수 있다.(Information Leakage)
해결 방안은 여러가지다. Generic한 컴포넌트를 보다 유연하게 만들어 주거나: 예를 들어 더 많은 사이즈 옵션을 지정해 놓는다. xs, s, m, l, xl, xxl, xxxl
. 근데 이 경우에도 크기가 또 추가되면 대규모 수정이 필요해 지므로 완벽하진 않지만 대부분의 경우 그렇게 까지 다양한 크기가 요구되지는 않는다.
직접 크기를 입력 받는 방법도 있는데 이 경우 기준이 없어서 나쁜 코드가 될 수도 있다. 대안으로 허용 가능한 크기를 지정해 놓는 방법이 있다.
UserAvatar.propTypes = {
size: PropTypes.oneOf(\[12, 14, 18, 24, 32, 36, 48\]);
}
혹은 TypeScript라면 다음과 같이 값을 제한할 수 있다.
type UserAvatarSize = 12 | 14 | 18 | 24 | 32 | 36 | 48;
interface UserAvatarProps {
size: UserAvatarSize
}
대략 이런식으로 버튼과 메뉴 컴포넌트가 있다고 할 때
다음과 같은 MenuButton이라는 컴포넌트가 있다고 하자
MenuButton 컴포넌트의 버튼이 눌렸을 때 메뉴가 열리고 버튼은 눌린 상태로 유지되어야한다면
아마 가장 첫번째로 드는 생각은 버튼에 isMenuOpen
이라는 속성(props)을 추가하는 것이다. 그러나 이렇게 하면 버튼이 메뉴에 관한 정보를 갖게 되므로 코드 스멜이라고 할 수 있다. 잘 생각해보면 버튼은 메뉴에 대해 알 필요가 없고 단순히 눌러진 상태인가 아닌가에 대해만 알면 된다. isMenuOpen
을 isPressed
로 바꾸기만 해도 훨씬 좋은 코드가 된다.
이처럼 이름 짓기는 생각보다 꽤 중요하다.
코드 리뷰시에는 항상 다음을 고민하자.
이게 저걸 알 필요가 있나?
[[Smells in React Apps 2 - Low Cohesion WIP]]에서 계속...